package cndw.core.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.Serializable;
import java.net.InetSocketAddress;

import cndw.core.dispatch.Request;
import cndw.core.dispatch.RequestBuilder;

public final class GameClient {
	private GameClientHandler clientHandler;
	private Channel channel;
	
	public static GameClient connect(String ip, int port) {
		return connect(ip, port, "TCP");
	}

	public static GameClient connect(String ip, int port, String way) {
		InetSocketAddress address = new InetSocketAddress(ip, port);
		return connect(address, way);
	}
	
	/**
	 * 连接到服务器
	 * @param address
	 * @return 连接成功后返回客户端,连接失败时返回null
	 */
	public static GameClient connect(InetSocketAddress address) {
		return connect(address, "TCP");
	}
	
	public static GameClient connect(InetSocketAddress address, String way) {
		final GameClientHandler handler = new GameClientHandler();
		ChannelFuture future = null;
		try {
			Bootstrap bootstrap = new Bootstrap();
			if ("TCP".equalsIgnoreCase(way)) {
				bootstrap.channel(NioSocketChannel.class);
			} else if ("UDP".equalsIgnoreCase(way)) {
				bootstrap.channel(NioDatagramChannel.class);
			}
			bootstrap.handler(new ChannelInitializer<Channel>() {
				@Override
				protected void initChannel(Channel channel) throws Exception {
					channel.pipeline().addLast(handler);
				}
			});
			future = bootstrap.connect(address);
		} catch (Exception e) {
			return null;
		}
		GameClient client = null;
		if (future != null) {
			future.awaitUninterruptibly();
			if (future.channel() != null && future.channel().isActive()) {
				client = new GameClient();
				client.clientHandler = handler;
				client.channel = future.channel();
			}
		}
		return client;
	}
	
	/**
	 * @param actionId
	 * @param params
	 */
	public synchronized void send(int actionId, Serializable...params) {
		Request request = RequestBuilder.create()
				.setActionId(actionId)
				.setParams(params)
				.build();
		send(request);
	}
	
	/**
	 * @param actionId
	 * @param params
	 * @param listener
	 */
	public synchronized void send(int actionId, Serializable[] params, ResponseListener listener) {
		Request request = RequestBuilder.create()
				.setActionId(actionId)
				.setParams(params)
				.build();
		send(request, listener);
	}
	
	/**
	 * @param actionId
	 * @param params
	 */
	public synchronized void sendAsSystem(int actionId, Serializable...params) {
		Request request = RequestBuilder.create()
				.setActionId(actionId)
				.setParams(params)
				.buildWithSign();
		send(request);
	}
	
	public synchronized void send(Request request) {
		if (channel.isActive())
			channel.write(request);
		else
			throw new RuntimeException("连接已关闭.");
	}
	
	public synchronized void send(Request request, ResponseListener listener) {
		if (channel != null && channel.isActive()) {
			clientHandler.registListener(request, listener);
			channel.write(request);
		} else
			throw new RuntimeException("连接已关闭.");
	}
	
	public synchronized void close() {
		if (channel != null)
			channel.close();
	}
}
